﻿using Soft.Data;
using Soft.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Soft.Service.Manager
{

    /// <summary>
    ///  ServerMapping管理(管理多个Server)
    /// </summary>
    public sealed class MappingManager : BaseService
    {

        public MappingManager() : base("System service map manager", "MappingManager")
        {
            Result result = NetManager.RegisterTcpServerChannel(NetManager.MappingServiceChannelName, NetManager.MappingPort);
            if (!result.Succeed)
            {
                this.OnError(result.Error);
            }
            result = NetManager.RegisterTcpClientChannel();
            if (!result.Succeed)
            {
                this.OnError(result.Error);
            }

            //设置接收广播
            this.mReceiveBroadcast = new ReceiveServiceInfoBroadcast();
            this.mReceiveBroadcast.Error += this.OnError;
            this.mReceiveBroadcast.ReceiveServiceInfo += this.MReceiveBroadcast_ReceiveServiceInfo;
            
            result = NetManager.RegisterServiceType<RemoteServerMappingPerformer>();
            if (!result.Succeed)
            {
                this.OnError(result.Error);
            }
        }

       
        internal new void OnError(Information error)
        {
            base.OnError(error);
        }

 
        /// <summary>
        /// 接收到广播后的数据 处理逻辑
        /// </summary>
        /// <param name="data"></param>
        private void MReceiveBroadcast_ReceiveServiceInfo(UdpBroadcastItem data)
        {
            string[] array = data.GetString().Split(new char[]
            {
                '|'
            });
            if (array.Length > 1 && array[0] == this.InstanceName)
            {
                MappingManager.ServerItem serverItem = new MappingManager.ServerItem
                {
                    Address = (IP)array[1]
                };
                if (serverItem.Address != IP.Empty)
                {
                    List<MappingManager.ServerItem> obj = this.mServers;
                    lock (obj)
                    {
                        if (!this.mServers.Contains(serverItem))
                        {
                            this.mServers.Add(serverItem);
                            base.WriteLog("Has been connected to one business service, the service IP address is: " + serverItem.Address.ToString() + ".", true);
                        }
                    }
                }
            }
        }


        internal bool MRemoteServerMappingPerformer_OnLogonVerify(string user, Guid session)
        {
            return true;
        }

  
        private Result LogonVerify(string user, Guid session)
        {
            return new Result();
        }


        internal ResultData<Guid> MRemoteServerMappingPerformer_UserLogin(string user, string password)
        {
            return new ResultData<Guid>
            {
                Data = Guid.NewGuid()
            };
        }

     
        internal void MRemoteServerMappingPerformer_UserLogoff(Guid session)
        {
        }


        /// <summary>
        /// 查找一个最好的Server来执行FucntionCode的功能号
        /// </summary>
        /// <param name="functionCode"></param>
        /// <returns></returns>
        internal ResultData<IP> MRemoteServerMappingPerformer_GetRemoteServerIP(string functionCode)
        {
            return this.GetPreferredServer(functionCode);
        }

 
        /// <summary>
        /// 启动
        /// </summary>
        /// <returns></returns>
        protected override Result OnStart()
        {
            Result result = new Result();
            //加载配置
            this.LoadConfiguration();
            //设置RemoteServerMapping执行器
            RemoteServerMappingPerformer.Mapping = this;
            //后台开启心跳检测，发送心跳信号
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.HeartbeatScan));
            //后台开启自动刷新服务器负载情况
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.RefreshServerSystemLoad));
            //开启接收udp广播
            this.mReceiveBroadcast.Start();
            return result;
        }


        /// <summary>
        /// 停止Mapping映射服务
        /// </summary>
        protected override void OnStop()
        {
            this.mReceiveBroadcast.Stop();
            RemoteServerMappingPerformer.Mapping = null;
            lock (this.mJobs)
            {
                foreach (string key in this.mJobs.Keys)
                {
                    this.mJobs[key].Dispose();
                }
                this.mJobs.Clear();
            }
            this.mServers.Clear();
        }


        /// <summary>
        /// 从含有FunctionCode  所有在线的Server中获取一个最好的服务器地址
        /// </summary>
        /// <param name="functionCode"></param>
        /// <returns></returns>
        private ResultData<IP> GetPreferredServer(string functionCode)
        {
            ResultData<IP> resultData = new ResultData<IP>();
            lock (this.mJobs)
            {
                if (this.mJobs.ContainsKey(functionCode))
                {
                    resultData.Data = this.mJobs[functionCode].OnlineServers.GetPreferredServer().Address;
                    if (this._Debug)
                    {
                        base.WriteLog(string.Concat(new string[]
                        {
                            "The service '",
                            resultData.Data.ToString(),
                            "' processes the function code '",
                            functionCode,
                            "'."
                        }), true);
                    }
                }
                else
                {
                    resultData.SetNotAuthorized(functionCode);
                    if (this._Debug)
                    {
                        base.WriteLog("Not found any service to support the function code '" + functionCode + "'.", true);
                    }
                }
            }
            return resultData;
        }


        /// <summary>
        /// 刷新系统负载情况
        /// </summary>
        /// <param name="stateInfo"></param>
        private void RefreshServerSystemLoad(object stateInfo)
        {
            while (!base.Terminated)
            {
                List<Task> list = new List<Task>();
                using (List<MappingManager.ServerItem>.Enumerator enumerator = this.mServers.GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        MappingManager.ServerItem server = enumerator.Current;
                        if (base.Terminated)
                        {
                            break;
                        }
                        if (server.State == MappingManager.InitializeState.Done)
                        {
                            list.Add(Task.Run(delegate ()
                            {
                                try
                                {
                                    //获取系统负载情况
                                    ResultJson resultJson = server.RemotePerformer.Invoke(new CallMethodInstruction(RemoteControlCode.GetSystemLoad.Code, ""));
                                    if (resultJson.Succeed)
                                    {
                                        server.SystemLoad = JsonConvertHelper.FormJson<GetSystemLoadResult>(resultJson.Json).SystemLoad;
                                    }
                                }
                                catch (Exception e)
                                {
                                    this.OnError(e);
                                }
                            }));
                        }
                    }
                }
                if (list.Count > 0)
                {
                    Task.WaitAll(list.ToArray());
                }
                if (base.Terminated)
                {
                    break;
                }
                base.Sleep(3, () => base.Terminated);
            }
        }


        /// <summary>
        /// 从其它的Server中获取job服务
        /// </summary>
        /// <param name="state"></param>
        private void AddJobFromServer(object state)
        {
            MappingManager.ServerItem server = (MappingManager.ServerItem)state;
            try
            {
                //获取远程服务器上的job列表
                ResultJson resultJson = server.RemotePerformer.Invoke(new CallMethodInstruction(RemoteControlCode.GetRemoteJobs.Code, ""));
                if (resultJson.Succeed)
                {
                    JsonConvertHelper.FormJson<List<GetJobsCommandResult>>(resultJson.Json).ForEach(delegate (GetJobsCommandResult e)
                    {
                        MappingManager.JobItem jobItem = null;
                        lock (this.mJobs)
                        {
                            if (this.mJobs.ContainsKey(e.FunctionCode))
                            {
                                jobItem = this.mJobs[e.FunctionCode];
                            }
                            else
                            {
                                jobItem = new MappingManager.JobItem
                                {
                                    FunctionCode = e.FunctionCode
                                };
                                this.mJobs.Add(e.FunctionCode, jobItem);
                            }
                        }
                       jobItem.OnlineServers.Add(server);
                    });
                    server.State = MappingManager.InitializeState.Done;
                }
                else
                {
                    this.OnError(resultJson);
                }
            }
            catch (Exception e)
            {
                lock (server)
                {
                    server.RemotePerformer = null;
                    server.State = MappingManager.InitializeState.Uninitiated;
                    server.FailedCount += 1UL;
                    if (server.FailedCount >= 3UL)
                    {
                        server.NextReconnectTime = DateTime.Now.AddSeconds(10.0);
                    }
                }
                this.OnError(e);
            }
        }


        /// <summary>
        /// 开启心跳检测
        /// </summary>
        /// <param name="stateInfo"></param>
        private void HeartbeatScan(object stateInfo)
        {
            //所有的服务器集合
            List<MappingManager.ServerItem> list = new List<MappingManager.ServerItem>();
            //异常的服务器集合
            List<MappingManager.ServerItem> list2 = new List<MappingManager.ServerItem>();
            while (!base.Terminated)
            {
                
                list.Clear();
                list2.Clear();
                lock (this.mServers)
                {
                    list.AddRange(this.mServers);
                }
                foreach (MappingManager.ServerItem serverItem in list)
                {
                    if (base.Terminated)
                    {
                        break;
                    }
                    //如果服务器未初始化，则发送请求
                    if (serverItem.State == MappingManager.InitializeState.Uninitiated)
                    {
                        if (serverItem.FailedCount >= 3UL)
                        {
                            if (serverItem.NextReconnectTime > DateTime.Now)
                            {
                                continue;
                            }
                            serverItem.FailedCount = 0UL;
                        }

                        //获取远程方法调用的的执行器
                        ResultData<ServiceRemoteMethodCallPerformer> remotingObject = NetManager.GetRemotingObject<ServiceRemoteMethodCallPerformer>(new TcpConnectIpAddress
                        {
                            IpAddress = serverItem.Address,
                            Port = NetManager.JobServicePort
                        });
                        if (!remotingObject.Succeed)
                        {
                            list2.Add(serverItem);
                            continue;
                        }
                        serverItem.RemotePerformer = remotingObject.Data;
                        //获取到远程方法执行器之后 将初始化状态设置为已连接
                        serverItem.State = MappingManager.InitializeState.Connected;
                        //后台 将从其它的Server中获取的job添加在jobs集合中
                        ThreadPool.QueueUserWorkItem(new WaitCallback(this.AddJobFromServer), serverItem);
                    }
                    //如果服务的初始状态为已完成，则发送心跳报文请求，判断请求结果是否正确
                    if (serverItem.State == MappingManager.InitializeState.Done)
                    {
                        HeartbeatCommandParams heartbeatCommandParams = new HeartbeatCommandParams
                        {
                            Flag = (uint)new Random().Next(10)
                        };
                        try
                        {
                            ResultJson resultJson = serverItem.RemotePerformer.Invoke(new CallMethodInstruction(RemoteControlCode.Heartbeat.Code, JsonConvertHelper.ToJson(heartbeatCommandParams)));
                            if (resultJson.Succeed)
                            {
                                HeartbeatCommandResult heartbeatCommandResult = JsonConvertHelper.FormJson<HeartbeatCommandResult>(resultJson.Json);
                                if (heartbeatCommandResult.Response != ~heartbeatCommandParams.Flag)
                                {
                                    list2.Add(serverItem);
                                }
                            }
                            else
                            {
                                list2.Add(serverItem);
                            }
                        }
                        catch
                        {
                            list2.Add(serverItem);
                        }
                    }
                }


                lock (this.mServers)
                {
                    list2.ForEach(delegate (MappingManager.ServerItem s)
                    {
                        if (this.mServers.Exists((MappingManager.ServerItem e) => e == s))
                        {
                            this.mServers.Remove(s);
                        }
                        //如果服务器异常，则移除该服务器的信息
                        lock (this.mJobs)
                        {
                            foreach (KeyValuePair<string, MappingManager.JobItem> keyValuePair in this.mJobs)
                            {
                                keyValuePair.Value.OnlineServers.Remove(s);
                            }
                            List<KeyValuePair<string, MappingManager.JobItem>> list3 = (from key in this.mJobs
                                                                                        where key.Value.OnlineServers.Count == 0
                                                                                        select key).ToList<KeyValuePair<string, MappingManager.JobItem>>();
                            foreach (KeyValuePair<string, MappingManager.JobItem> keyValuePair2 in list3)
                            {
                                this.mJobs.Remove(keyValuePair2.Key);
                            }
                        }
                    });
                }
                base.Sleep(1, null);
            }
        }


        /// <summary>
        /// 加载配置
        /// </summary>
        private void LoadConfiguration()
        {
            MappingServiceConfig mappingServiceConfig = new MappingServiceConfig();
            mappingServiceConfig.Load();
            this._Debug = mappingServiceConfig.Debug;
            this.InstanceName = mappingServiceConfig.InstanceName;
            RemoteServerMappingPerformer._InstanceName = this.InstanceName;
        }

     
        private const int REFRESH_SERVICE_LOAD_INTERVAL_SECOND = 3;


        private const int REFRESH_SERVER_INTERVAL_SECOND = 1;


        private const int MAX_CONNECT_ERROR_COUNT = 3;


        private const int RECONNECT_INTERVAL_SECOND = 10;


        private string InstanceName = "SEFAJOBSERVICE";


        private bool _Debug;


        /// <summary>
        /// 提供服务的服务器列表
        /// </summary>
        private List<MappingManager.ServerItem> mServers = new List<MappingManager.ServerItem>();


       /// <summary>
       ///  功能号对应的服务器列表有哪些  [FunctionCode,JobItem]
       /// </summary>
        private SortedList<string, MappingManager.JobItem> mJobs = new SortedList<string, MappingManager.JobItem>();


        /// <summary>
        /// 接收消息的UDP广播
        /// </summary>
        private ReceiveServiceInfoBroadcast mReceiveBroadcast;


        private sealed class JobItem : SoftObject, IDisposable
        {

            ~JobItem()
            {
                this.Dispose();
            }

            public int CompareTo(MappingManager.JobItem other)
            {
                return this.FunctionCode.CompareTo(other.FunctionCode);
            }

            public void Dispose()
            {
                this.OnlineServers.Dispose();
            }

            public string FunctionCode = string.Empty;


            /// <summary>
            /// 在线的服务器
            /// </summary>
            public MappingManager.ServerCollection OnlineServers = new MappingManager.ServerCollection();
        }


        /// <summary>
        /// 初始化的状态
        /// </summary>
        private enum InitializeState
        {
            /// <summary>
            /// 未初始化
            /// </summary>
            Uninitiated,
            /// <summary>
            /// 已连接
            /// </summary>
            Connected,
            /// <summary>
            /// 完成
            /// </summary>
            Done
        }


        /// <summary>
        /// 标识一个提供的服务的服务器
        /// </summary>
        private sealed class ServerItem : SoftObject, IComparable<MappingManager.ServerItem>, IEquatable<MappingManager.ServerItem>, IDisposable
        {

            ~ServerItem()
            {
                this.Dispose();
            }

            public int CompareTo(MappingManager.ServerItem other)
            {
                return this.SystemLoad.CompareTo(other.SystemLoad);
            }

            public bool Equals(MappingManager.ServerItem other)
            {
                return other != null && this.Address == other.Address;
            }

            public override bool Equals(object obj)
            {
                return obj != null && obj.GetType() == base.GetType() && this.Equals((MappingManager.ServerItem)obj);
            }

            public override int GetHashCode()
            {
                return this.Address.GetHashCode();
            }

            public void Dispose()
            {
                try
                {
                    if (this.RemotePerformer != null)
                    {
                        this.RemotePerformer.Dispose();
                        this.RemotePerformer = null;
                    }
                }
                catch
                {
                }
            }


            /// <summary>
            /// 初始化的状态
            /// </summary>
            public MappingManager.InitializeState State;


            /// <summary>
            /// 服务端IP地址
            /// </summary>
            public IP Address = IP.Empty;

        
            /// <summary>
            /// 服务端的负载情况
            /// </summary>
            public double SystemLoad = double.MaxValue;

 
            /// <summary>
            /// 远程方法调用执行器
            /// </summary>
            public ServiceRemoteMethodCallPerformer RemotePerformer;


            /// <summary>
            /// 失败的次数
            /// </summary>
            public ulong FailedCount;


            /// <summary>
            /// 下一次连接时间
            /// </summary>
            public DateTime NextReconnectTime = DateTime.MinValue;


        }


        /// <summary>
        /// 可以提供服务的服务器集合
        /// </summary>
        private sealed class ServerCollection : List<MappingManager.ServerItem>, IDisposable
        {

            ~ServerCollection()
            {
                this.Dispose();
            }


            /// <summary>
            ///获取一个最好的服务器 [根据服务器的负载情况]
            /// </summary>
            /// <returns></returns>
            public MappingManager.ServerItem GetPreferredServer()
            {
                Random random = new Random();
                if (base.Count <= 3)
                {
                    return base[random.Next(0, base.Count)];
                }
                base.Sort((MappingManager.ServerItem a, MappingManager.ServerItem b) => a.SystemLoad.CompareTo(b.SystemLoad));
                return base[random.Next(0, 4)];
            }


            public new void Clear()
            {
                base.ForEach(delegate (MappingManager.ServerItem e)
                {
                    e.Dispose();
                });
                base.Clear();
            }


            public void Dispose()
            {
                this.Clear();
            }


            private const int MIN_RECORD_COUNT = 3;


        }

    }
}
